package com.zgx.plus.system.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.zgx.plus.common.aop.DataScope;
import com.zgx.plus.common.constant.ComConstant;
import com.zgx.plus.common.exception.BizException;
import com.zgx.plus.common.utils.SecurityUtils;
import com.zgx.plus.system.api.dto.SysRoleDto;
import com.zgx.plus.system.api.pos.SysRole;
import com.zgx.plus.system.api.pos.SysRoleDept;
import com.zgx.plus.system.api.pos.SysRoleMenu;
import com.zgx.plus.system.api.pos.SysUserRole;
import com.zgx.plus.system.api.vos.SysRoleVo;
import com.zgx.plus.system.api.vos.SysUserRoleVo;
import com.zgx.plus.system.mapper.SysRoleDeptMapper;
import com.zgx.plus.system.mapper.SysRoleMapper;
import com.zgx.plus.system.mapper.SysUserRoleMapper;
import com.zgx.plus.system.service.SysRoleDeptService;
import com.zgx.plus.system.service.SysRoleMenuService;
import com.zgx.plus.system.service.SysRoleService;
import com.zgx.plus.system.service.SysUserRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

    @Autowired
    private SysRoleMenuService sysRoleMenuService;
    @Autowired
    private SysRoleDeptService sysRoleDeptService;
    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysUserRoleMapper userRoleMapper;

    @Autowired
    private SysRoleDeptMapper roleDeptMapper;


    /**
     * 根据条件分页查询角色数据
     *
     * @param role 角色信息
     * @return 角色数据集合信息
     */
    @Override
    @DataScope(deptAlias = "d")
    public List<SysRoleVo> selectRoleList(SysRoleDto role) {
        Long roleId = role.getRoleId();
        Object obj = role.getParams().get(ComConstant.KEY_DATA_SCOPE);
        String dataScopeSql = Objects.isNull(obj) ? null : (StrUtil.removePrefix(String.valueOf(obj).trim(), "AND"));

        return Convert.toList(SysRoleVo.class, this.list(Wrappers.lambdaQuery(SysRole.class).eq(SysRole::getDelFlag, 0)
                .eq((Objects.nonNull(roleId) && !Objects.equals(roleId, 0L)), SysRole::getRoleId, roleId)
                .eq(StrUtil.isNotBlank(role.getStatus()), SysRole::getStatus, role.getStatus())
                .like(StrUtil.isNotBlank(role.getRoleName()), SysRole::getRoleName, role.getRoleName())
                .like(StrUtil.isNotBlank(role.getRoleKey()), SysRole::getRoleKey, role.getRoleKey())
                .apply(StrUtil.isNotBlank(dataScopeSql), dataScopeSql)
                .orderByAsc(Collections.singletonList(SysRole::getRoleSort))));
    }

    /**
     * 通过角色ID查询角色
     *
     * @param roleId 角色ID
     * @return 角色对象信息
     */
    @Override
    public SysRoleVo selectRoleById(Long roleId) {
        if (!SecurityUtils.isCurrentUserAdmin()) {
            if (!SqlHelper.retBool(this.count(Wrappers.lambdaQuery(SysRole.class).eq(SysRole::getDelFlag, 0).eq(SysRole::getRoleId, roleId)))) {
                throw new BizException("没有权限访问角色数据！");
            }
        }
        this.checkRoleDataScope(roleId);
        return Convert.convert(SysRoleVo.class, this.getById(roleId));
    }

    /**
     * 新增保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    @Transactional
    public boolean insertRole(SysRoleVo role) {
        this.checkRoleNameRoleKey(role);
        this.save(role);
        return insertRoleMenu(role);
    }

    /**
     * 修改保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    @Transactional
    public boolean updateRole(SysRoleVo role) {
        Assert.isFalse(Objects.nonNull(role.getRoleId()) && role.isAdmin(), () -> new BizException("不允许操作超级管理员角色"));
        this.checkRoleNameRoleKey(role);
        this.checkRoleDataScope(role.getRoleId());
        // 修改角色信息
        this.updateById(role);
        // 删除角色与菜单关联
        sysRoleMenuService.removeById(role.getRoleId());
        return insertRoleMenu(role);
    }

    /**
     * 修改数据权限信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    @Transactional
    public boolean authDataScope(SysRoleVo role) {
        Assert.isFalse(Objects.nonNull(role.getRoleId()) && role.isAdmin(), () -> new BizException("不允许操作超级管理员角色"));
        this.checkRoleDataScope(role.getRoleId());
        // 修改角色信息
        this.updateById(role);
        // 删除角色与部门关联
        sysRoleDeptService.removeById(role.getRoleId());
        // 新增角色和部门信息（数据权限）
        return insertRoleDept(role);
    }

    /**
     * 修改角色状态
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public boolean updateRoleStatus(SysRoleVo role) {
        Assert.isFalse(Objects.nonNull(role.getRoleId()) && role.isAdmin(), () -> new BizException("不允许操作超级管理员角色"));
        this.checkRoleDataScope(role.getRoleId());
        return this.updateById(role);
    }

    /**
     * 批量删除角色信息
     *
     * @param roleIds 需要删除的角色ID
     * @return 结果
     */
    @Override
    @Transactional
    public boolean deleteRoleByIds(Long[] roleIds) {
        for (Long roleId : roleIds) {
            SysRoleVo role = new SysRoleVo();
            role.setRoleId(roleId);
            Assert.isFalse(Objects.nonNull(role.getRoleId()) && role.isAdmin(), () -> new BizException("不允许操作超级管理员角色"));
            this.checkRoleDataScope(role.getRoleId());


            boolean retBool = SqlHelper.retBool(sysUserRoleService.count(Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getRoleId, roleId)));
            Assert.isFalse(retBool, () -> new BizException(MessageFormat.format("{0}角色已被分配，不能删除", roleId)));
        }
        // 删除角色与菜单关联
        sysRoleMenuService.removeBatchByIds(Arrays.asList(roleIds));
        // 删除角色与部门关联
        sysRoleDeptService.removeBatchByIds(Arrays.asList(roleIds));
        return this.removeBatchByIds(Arrays.asList(roleIds));
    }

    /**
     * 查询所有角色
     *
     * @return 角色列表
     */
    @Override
    public List<SysRoleVo> selectRoleAll() {
        return selectRoleList(SysRoleDto.builder().build());
    }

    /**
     * 批量选择授权用户角色
     *
     * @param roleId  角色ID
     * @param userIds 需要授权的用户数据ID
     * @return 结果
     */
    @Override
    public boolean insertAuthUsers(Long roleId, Long[] userIds) {
        this.checkRoleDataScope(roleId);
        // 新增用户与角色管理
        List<SysUserRole> list = Arrays.stream(userIds).map(userId -> new SysUserRole(userId, roleId)).collect(Collectors.toList());
        return sysUserRoleService.saveBatch(list);
    }

    /**
     * 取消授权用户角色
     *
     * @param userRole 用户和角色关联信息
     * @return 结果
     */
    @Override
    public boolean deleteAuthUser(SysUserRoleVo userRole) {
        return sysUserRoleService.remove(Wrappers.lambdaQuery(SysUserRole.class)
                .eq(SysUserRole::getRoleId, userRole.getRoleId())
                .eq(SysUserRole::getUserId, userRole.getUserId()));
    }

    /**
     * 批量取消授权用户角色
     *
     * @param roleId  角色ID
     * @param userIds 需要取消授权的用户数据ID
     * @return 结果
     */
    @Override
    public boolean deleteAuthUsers(Long roleId, Long[] userIds) {
        return sysUserRoleService.remove(Wrappers.lambdaQuery(SysUserRole.class)
                .eq(SysUserRole::getRoleId, roleId)
                .in(SysUserRole::getUserId, Arrays.asList(userIds)));
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectRolePermissionByUserId(Long userId) {
        // 获取用户角色
        List<Long> roleIds = sysUserRoleService.listByIds(Collections.singletonList(userId)).stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
        // 根据ID获取用户角色RoleKey
        return this.listObjs(Wrappers.lambdaQuery(SysRole.class).select(SysRole::getRoleKey).in(SysRole::getRoleId, roleIds).eq(SysRole::getDelFlag, ComConstant.FLAG_EXIST),
                roleKey -> Objects.isNull(roleKey) ? null : String.valueOf(roleKey)).stream().filter(Objects::nonNull).collect(Collectors.toSet());
    }

// /**
//  * 根据用户ID查询角色
//  *
//  * @param userId 用户ID
//  * @return 角色列表
//  */
// @Override
// public List<SysRole> selectRolesByUserId(Long userId) {
//  List<SysRole> userRoles = roleMapper.selectRolePermissionByUserId(userId);
//  List<SysRoleVo> roles = selectRoleAll();
//  for (SysRole role : roles) {
//   for (SysRole userRole : userRoles) {
//    if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
//     role.setFlag(true);
//     break;
//    }
//   }
//  }
//  return roles;
// }
//
//
//
// /**
//  * 根据用户ID获取角色选择框列表
//  *
//  * @param userId 用户ID
//  * @return 选中角色ID列表
//  */
// @Override
// public List<Long> selectRoleListByUserId(Long userId) {
//  return roleMapper.selectRoleListByUserId(userId);
// }
//
//
// /**
//  * 校验角色名称是否唯一
//  *
//  * @param role 角色信息
//  * @return 结果
//  */
// @Override
// public boolean checkRoleNameUnique(SysRole role) {
//  Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
//  SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName());
//  if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
//   return UserConstants.NOT_UNIQUE;
//  }
//  return UserConstants.UNIQUE;
// }
//
// /**
//  * 校验角色权限是否唯一
//  *
//  * @param role 角色信息
//  * @return 结果
//  */
// @Override
// public boolean checkRoleKeyUnique(SysRole role) {
//  Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
//  SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey());
//  if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
//   return UserConstants.NOT_UNIQUE;
//  }
//  return UserConstants.UNIQUE;
// }
//
// /**
//  * 校验角色是否允许操作
//  *
//  * @param role 角色信息
//  */
// @Override
// public void checkRoleAllowed(SysRole role) {
//  if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin()) {
//   throw new ServiceException("不允许操作超级管理员角色");
//  }
// }
//
//
// /**
//  * 通过角色ID查询角色使用数量
//  *
//  * @param roleId 角色ID
//  * @return 结果
//  */
// @Override
// public int countUserRoleByRoleId(Long roleId) {
//  return userRoleMapper.countUserRoleByRoleId(roleId);
// }
//
//
// /**
//  * 通过角色ID删除角色
//  *
//  * @param roleId 角色ID
//  * @return 结果
//  */
// @Override
// @Transactional
// public int deleteRoleById(Long roleId) {
//  // 删除角色与菜单关联
//  roleMenuMapper.deleteRoleMenuByRoleId(roleId);
//  // 删除角色与部门关联
//  roleDeptMapper.deleteRoleDeptByRoleId(roleId);
//  return roleMapper.deleteRoleById(roleId);
// }


    /**
     * @param role 检查角色名称和角色权限
     */
    private void checkRoleNameRoleKey(SysRoleVo role) {
        boolean retBool = SqlHelper.retBool(this.count(Wrappers.lambdaQuery(SysRole.class)
                .eq(SysRole::getRoleName, role.getRoleName()).eq(SysRole::getDelFlag, ComConstant.FLAG_EXIST)));
        Assert.isFalse(retBool, () -> new BizException(MessageFormat.format("新增角色{0}失败，角色名称已存在", role.getRoleName())));

        boolean retBoolRolekey = SqlHelper.retBool(this.count(Wrappers.lambdaQuery(SysRole.class)
                .eq(SysRole::getRoleKey, role.getRoleKey()).eq(SysRole::getDelFlag, ComConstant.FLAG_EXIST)));
        Assert.isFalse(retBoolRolekey, () -> new BizException(MessageFormat.format("新增角色{0}失败，角色权限已存在", role.getRoleKey())));
    }

    /**
     * 新增角色菜单信息
     *
     * @param role 角色对象
     */
    private boolean insertRoleMenu(SysRoleVo role) {
        // 新增用户与角色管理
        if (Objects.nonNull(role.getMenuIds())) {
            List<SysRoleMenu> list = Arrays.stream(role.getMenuIds()).map(menuId -> {
                SysRoleMenu rm = new SysRoleMenu();
                rm.setRoleId(role.getRoleId());
                rm.setMenuId(menuId);
                return rm;
            }).collect(Collectors.toList());
            if (list.size() > 0) {
                return sysRoleMenuService.saveBatch(list);
            }
        }
        return true;
    }

    /**
     * 新增角色部门信息(数据权限)
     *
     * @param role 角色对象
     */
    private boolean insertRoleDept(SysRoleVo role) {
        // 新增角色与部门（数据权限）管理
        if (Objects.nonNull(role.getDeptIds())) {
            List<SysRoleDept> list = Arrays.stream(role.getMenuIds()).map(deptId -> {
                SysRoleDept rm = new SysRoleDept();
                rm.setRoleId(role.getRoleId());
                rm.setDeptId(deptId);
                return rm;
            }).collect(Collectors.toList());
            if (list.size() > 0) {
                return sysRoleDeptService.saveBatch(list);
            }
        }
        return true;
    }


    /**
     * 校验角色是否有数据权限
     *
     * @param roleId 角色id
     */
    public void checkRoleDataScope(Long roleId) {
        if (!SecurityUtils.isCurrentUserAdmin()) {
            boolean retBool = SqlHelper.retBool(this.count(Wrappers.lambdaQuery(SysRole.class).eq(SysRole::getRoleId, roleId).eq(SysRole::getDelFlag, ComConstant.FLAG_EXIST)));
            Assert.isTrue(retBool, () -> new BizException("没有权限访问角色数据！"));
        }
    }
}
